package scala.pickling.binary.list.int

import scala.language.higherKinds

import scala.pickling._
import binary._
import reflect.runtime.universe._
import scala.collection.mutable.ListBuffer

import org.scalatest.FunSuite

class HandwrittenListIntPicklerUnpickler[Coll[_] <: List[_]](val format: PickleFormat)
    extends SPickler[Coll[Int]] with Unpickler[Coll[Int]] {

  def pickle(picklee: Coll[Int], builder: PBuilder): Unit = {
    builder.beginEntry()
    val arr = picklee.toArray
    val length = arr.length
    builder.beginCollection(arr.length)
    builder.hintStaticallyElidedType()
    builder.hintTag(FastTypeTag.Int)
    builder.pinHints()

    var i: Int = 0
    while (i < length) {
      builder.beginEntry(arr(i))
      builder.endEntry()
      i = i + 1
    }

    builder.unpinHints()
    builder.endCollection(i)
    builder.endEntry()
  }

  def unpickle(tag: => FastTypeTag[_], reader: PReader): Any = {
    val arrReader = reader.beginCollection()
    arrReader.hintStaticallyElidedType()
    arrReader.hintTag(FastTypeTag.Int)
    arrReader.pinHints()

    val buffer = ListBuffer[Int]()
    val length = arrReader.readLength()
    var i = 0
    while (i < length) {
      arrReader.beginEntry()
      buffer += arrReader.readPrimitive().asInstanceOf[Int]
      arrReader.endEntry()
      i = i + 1
    }

    arrReader.unpinHints()
    arrReader.endCollection()
    buffer.toList
  }
}

class BinaryListIntTest extends FunSuite {
  test("main") {
    implicit def genListPickler[Coll[_] <: List[_]](implicit format: PickleFormat): SPickler[Coll[Int]] with Unpickler[Coll[Int]] =
      new HandwrittenListIntPicklerUnpickler(format)

    val l = List[Int](7, 24, 30)
    val pckl = l.pickle
    assert(pckl.value.asInstanceOf[Array[Byte]].mkString("[", ",", "]") === "[0,0,0,50,115,99,97,108,97,46,99,111,108,108,101,99,116,105,111,110,46,105,109,109,117,116,97,98,108,101,46,36,99,111,108,111,110,36,99,111,108,111,110,91,115,99,97,108,97,46,73,110,116,93,0,0,0,3,0,0,0,7,0,0,0,24,0,0,0,30]")
    assert(pckl.unpickle[List[Int]] === List(7, 24, 30))
  }
}
